
'use strict'

const fs        = require('node:fs')
const path      = require('node:path')
const Koa       = require('koa')
const koaBody   = require('koa-body').koaBody
const Router    = require('koa-router')
const koaStatic = require('koa-static')
const xlsx      = require('node-xlsx')
const chokidar  = require('chokidar')
const LRUCache  = require('lru-cache')
const toml      = require('@iarna/toml')
const sharp = require('sharp')

const CHARSET   = 'utf-8'

const options   = { max : 500 }
const cache     = new LRUCache.LRUCache(options)
const app       = new Koa()
const router    = new Router()

const config    = toml.parse(fs.readFileSync('config.toml', 'utf8'))

let db          = {}

// 记录搜索历史
class SearchHistory{

    max = 500
    store = []
    number = config['system']['keyword']

    record(keyword){

        let record = false

        for(let elem of this.store){
            if(keyword === elem.value){
                elem.count++
                record = true
            }
        }

        if(!record){
            this.store.push({
                value : keyword,
                count : 1,
            })
        }


        if(this.store.length === this.max){
            // 达到上限, 出一半
            this.store = this.store.sort((a, b)=>b.count - a.count)
            
            let store = []
            for(let i = 0; i < max / 2; i++){
                store.push(this.store[i])
            }
            this.store = store
        }
    }
    list(){
        let res = []
        this.store = this.store.sort((a, b)=>b.count - a.count)
        // console.log(this.store)
        for(let i = 0; i < this.number; i++){
            try{ res.push(this.store[i].value) }catch(e){}
           
        }
        // console.log(res)
        return res
    }
}

let searchHistory = new SearchHistory()

// 加载资源
const load      = async (path_, size)=>{

    const inner = async path_=>{
        if(/(\.jpg$)|(\.jpeg$)|(\.png$)/i.test(path_)){
            const ext = path.extname(path_).toLowerCase().replace(/^\./, '')
            // console.log(ext)
            let img = await fs.promises.readFile(path_)
            // let img = (await fs.promises.readFile(path_)).toString('base64')
            // console.log(img)
            // console.log(size)
            if(undefined !== size){
                return new Promise(r=>{
                    sharp(img)
                    .resize(300, 400)
                    .toBuffer()
                    .then(data=>{
                        
                        return r(`data:image/${ext};base64,${data.toString('base64')}`)
                    })
                })
            }
            return new Promise(r=>r(`data:image/${ext};base64,${img.toString('base64')}`))
        }else if(/\.txt$/i.test(path_)){
            const data = await fs.promises.readFile(path_, CHARSET)
            return new Promise(r=>r(data))
        }
    }

    path_ = path.normalize(path_)

    // console.log(path_)

    if(cache.has(path_)){
        let val = cache.get(path_)
        let mtime = (await fs.promises.stat(path_)).mtime

        
        if(mtime !== val.mtime){
            val.data = await inner(path_)
            // console.log(53333)
            // 更新缓存
            cache.set(path_, val)
            return new Promise(r=>r(val.data))
        }
    }else{
        try{
            let stat = await fs.promises.stat(path_)

            let val = {}
            val.mtime = stat.mtime
            val.data = await inner(path_)

            // console.log(val.data)

            cache.set(path_, val)

            return new Promise(r=>r(val.data))
        }catch(e){
            // console.log(111, e)
            return new Promise(r=>r(null))
        }

    }
    
}

chokidar.watch('./data').on('all', (evt, path_)=>{
    if(/\.xlsx$/i.test(path_) && '~$' !== path.basename(path_).substring(0, 2)){

        try{
            let data = xlsx.parse(path_)[0].data
            let titleList = data.shift()
            for(let row of data){

                let obj = {}

                for(let i = 0; i < titleList.length; i++){
                    obj[titleList[i]] = row[i]
                }

                db[obj['姓名']] = db[obj['姓名']] || {}
                db[obj['姓名']] = Object.assign(db[obj['姓名']], obj)
            }
            // console.log(db)
        }catch(e){}
    }
})

app.use(koaBody({
    multipart : true
}))

router.get('/hot_word', async ctx=>{
    ctx.body = {
        historyList : searchHistory.list(),
        areaList :  config['system']['type'],
    }
})

router.get('/title', async ctx=>{
    ctx.body = config['system']['title']
})

router.post('/search', async ctx=>{

    let res = []

    searchHistory.record(ctx.request.body.search)

    for(let key in db){
        let val = db[key]
        let name = val['姓名'] || ''
        let office = val['职务'] || ''
        let obj = null
        if(name.indexOf(ctx.request.body.search) > -1){
            obj = db[key]
        }else if(office.indexOf(ctx.request.body.search) > -1){
            obj = db[key]
        }
        if(null !== obj){
            let obj2 = {}
            for(let key in obj){
                if('*' === key[0]){

                    // console.log(55555, obj[key])
                    obj2[key] = await load(path.join('data', obj[key]), [300, 420])
                }else{
                    obj2[key] = obj[key]
                }
            }
            if(obj2['*头像'] === null){
                // console.log(2222)
                obj2['*头像'] = await load('img.jpg', [300, 420])
            }
            res.push(obj2)
        }
    }

    ctx.body = res
})

app.use(router.routes())
app.use(router.allowedMethods())

app.use(koaStatic(path.join(__dirname, '/static')))

app.listen(80)